1 00:00:00,660 --> 00:00:03,150 Welcome back to part two of scripting our AI. 2 00:00:03,180 --> 00:00:07,920 We're going to jump right back into where we left off, which was determining what to do when our AI 3 00:00:07,950 --> 00:00:10,470 gets a target or gets no target at all. 4 00:00:10,830 --> 00:00:16,290 So if our AI does sense a target and it's visible and the AI can see them and they're the closest target, 5 00:00:16,290 --> 00:00:22,860 then we actually need to go ahead and have the AI path find or start chasing that particular player. 6 00:00:22,860 --> 00:00:27,750 So what we could do is we could create a function and we could call it something like New Path two, 7 00:00:27,750 --> 00:00:31,800 and we would pass the target that we need to go ahead and path find towards. 8 00:00:31,800 --> 00:00:36,810 So we would pass our target and this function would basically handle the rest for us. 9 00:00:36,810 --> 00:00:40,200 So we could go ahead and create this new function, call it new path two. 10 00:00:40,230 --> 00:00:46,920 We get a target and this is where we would start either pathfinding towards that target or directly 11 00:00:46,920 --> 00:00:52,500 chasing after that target if we can see them clearly, and before we also start chasing or creating 12 00:00:52,500 --> 00:00:57,900 a path towards this target, we also want to go ahead and update the walk speed of our humanoid. 13 00:00:57,900 --> 00:01:03,090 So my humanoid walk speed and set it equal to the AI properties dot chase speed. 14 00:01:03,330 --> 00:01:08,280 And just to make this autofill a little bit easier, I'm actually going to go ahead and take our handsome 15 00:01:08,280 --> 00:01:13,710 Squidward AI and put him back inside of the other stuff folder inside of server storage. 16 00:01:13,710 --> 00:01:15,990 That way we can actually refer to him properly. 17 00:01:16,490 --> 00:01:21,080 But after we set them to the chase speed, we need to start pathfinding to our target. 18 00:01:21,320 --> 00:01:22,730 So to Pathfind to our target. 19 00:01:22,730 --> 00:01:25,250 This is where we're going to have to use our pathfinding service. 20 00:01:25,250 --> 00:01:28,700 And there's a function in there called Create Path. 21 00:01:28,820 --> 00:01:36,410 This is where we basically create a new path instance where we can go ahead and compute waypoints based 22 00:01:36,410 --> 00:01:37,820 on two different positions. 23 00:01:37,820 --> 00:01:41,750 And this function has to get past a table called agent Parameters. 24 00:01:41,750 --> 00:01:48,380 And this lets you fine tune the path for the size of the agent, or aka the humanoid, or our AI that's 25 00:01:48,380 --> 00:01:51,080 going to be pathfinding along this path. 26 00:01:51,080 --> 00:01:55,070 So that means inside of our properties module script, we're going to have to create a new section in 27 00:01:55,070 --> 00:01:59,510 here to define all of the different agent parameters for pathfinding. 28 00:02:00,090 --> 00:02:04,530 So what I'm going to do is down here, I'm going to create a key. 29 00:02:04,530 --> 00:02:06,720 I'm going to call it Agent Parameters. 30 00:02:08,000 --> 00:02:09,590 And we'll set it equal to a table. 31 00:02:09,590 --> 00:02:13,550 Instead of this table, we're going to have to define a bunch of different key value pairs. 32 00:02:13,550 --> 00:02:16,820 One of those is going to be called agent Radius. 33 00:02:16,820 --> 00:02:19,340 And we're going to set this at two studs. 34 00:02:19,340 --> 00:02:20,510 What does this represent. 35 00:02:20,510 --> 00:02:25,280 Well this basically represents the width of our AI or our character right. 36 00:02:25,280 --> 00:02:27,200 How wide is our character. 37 00:02:27,200 --> 00:02:31,790 And this helps to determine basically the different areas that our AI can pathfind. 38 00:02:31,820 --> 00:02:36,860 Because let's say there's a hole in the map, it's tall enough, but it's not wide enough. 39 00:02:36,860 --> 00:02:43,970 Well, we can use the agent radius to determine the minimum radius between two parts that our AI can 40 00:02:43,970 --> 00:02:45,020 pathfind to. 41 00:02:45,140 --> 00:02:52,820 So since the width of our AI is about four studs, then that means our AI has to find a path that has 42 00:02:52,820 --> 00:02:56,660 a minimum width of four studs to be able to pathfind through it. 43 00:02:56,840 --> 00:03:03,530 Another one is called agent height, which determines the height or the minimum height that the AI has 44 00:03:03,530 --> 00:03:04,520 to pathfind through. 45 00:03:04,520 --> 00:03:08,690 And since our AI is about six studs tall, we're going to set this to six. 46 00:03:09,700 --> 00:03:14,890 Another thing we need to determine is whether or not we can jump. 47 00:03:14,890 --> 00:03:17,680 So we can call this agent can jump. 48 00:03:17,680 --> 00:03:19,360 And we're going to set this to true. 49 00:03:19,360 --> 00:03:25,750 And this is just in case for some reason when your AI is pathfinding, it needs to be able to jump to 50 00:03:25,750 --> 00:03:27,730 get to a particular area. 51 00:03:28,380 --> 00:03:31,170 Another one is called Agent Can Climb. 52 00:03:31,170 --> 00:03:36,000 Now, I don't anticipate our AI being able to climb anything because there's nothing to climb in the 53 00:03:36,000 --> 00:03:37,860 basement, so we're just going to set this to false. 54 00:03:38,550 --> 00:03:44,130 And another thing we need to determine is something called waypoint spacing. 55 00:03:44,130 --> 00:03:50,970 And this determines basically how far apart should each of the waypoints be when it calculates between 56 00:03:50,970 --> 00:03:52,410 two different positions. 57 00:03:52,410 --> 00:03:58,920 I found four studs to be pretty good, but if you want your, um, path to be more detailed, then you 58 00:03:58,920 --> 00:04:00,900 would reduce this number to something like one. 59 00:04:00,900 --> 00:04:06,750 So each time it would move one stud and your path would be super detailed. 60 00:04:06,750 --> 00:04:08,970 Four studs I found to be pretty good. 61 00:04:09,360 --> 00:04:13,860 The last thing we want to define inside of the agent parameters is a table called costs. 62 00:04:14,340 --> 00:04:20,730 And this table basically defines, um, a bunch of different materials and their costs to traverse over 63 00:04:20,730 --> 00:04:20,880 them. 64 00:04:20,880 --> 00:04:27,660 So basically you could use this table as a custom way of making your AI avoid particular materials. 65 00:04:27,660 --> 00:04:33,030 So for example you would like the AI to walk over wood more than it would rock. 66 00:04:33,030 --> 00:04:37,920 So you would define in here, um, that material and the cost to walk over it. 67 00:04:37,920 --> 00:04:39,270 We don't really care about that. 68 00:04:39,270 --> 00:04:41,250 So we're just going to leave this blank. 69 00:04:41,840 --> 00:04:46,910 But now that we've created this agent parameters, what we can do is we can go back and we can pass 70 00:04:46,910 --> 00:04:49,700 that agent parameters to our create path function. 71 00:04:49,700 --> 00:04:53,270 So we can refer to AI properties and pass agent parameters. 72 00:04:53,510 --> 00:04:57,440 And this will go ahead and return back to us a path instance. 73 00:04:58,100 --> 00:05:06,020 And using this path instance what we can do is we can use a function in there called compute async. 74 00:05:06,020 --> 00:05:12,800 So actually if I denote this here as a path and then I can go ahead and try again. 75 00:05:12,800 --> 00:05:13,190 There we go. 76 00:05:13,190 --> 00:05:15,170 We get our compute async function. 77 00:05:15,170 --> 00:05:18,530 We get a start vector three and a finishing vector three. 78 00:05:18,530 --> 00:05:22,130 So our start vector three is going to be my route part dot position. 79 00:05:22,130 --> 00:05:26,480 And the place we want to path find towards is going to be our target dot position. 80 00:05:27,110 --> 00:05:32,390 So this is going to sit here and compute the path and try to figure out the best way to get from this 81 00:05:32,390 --> 00:05:37,370 position to this position, and then it'll tell you whether or not it was successful in creating this 82 00:05:37,370 --> 00:05:37,940 path. 83 00:05:37,940 --> 00:05:40,550 So if the path dot status. 84 00:05:41,240 --> 00:05:45,230 Is not equal to the enum dot path status dot success. 85 00:05:45,230 --> 00:05:50,750 So if we were not successful in pathfinding towards this player, then we've run into a problem. 86 00:05:50,750 --> 00:05:55,970 Either our AI could possibly be stuck, or there's something else weird going on. 87 00:05:55,970 --> 00:06:00,650 So just in case, for some reason our AI is stuck, what we could do is we could refer to my humanoid 88 00:06:00,770 --> 00:06:06,380 and set the jump property equal to true to make our AI jump, we'll wait something like 0.1 seconds, 89 00:06:06,380 --> 00:06:11,360 and then we're just going to return out of this function and try to find a different player to pathfind 90 00:06:11,360 --> 00:06:11,960 towards. 91 00:06:12,860 --> 00:06:13,490 Otherwise. 92 00:06:13,490 --> 00:06:18,410 If we were successful and calculating a path, then what we could do is we could get all the waypoints 93 00:06:18,410 --> 00:06:22,730 for this path, which is equal to path, get waypoints. 94 00:06:23,430 --> 00:06:28,260 And what we're going to do is we're going to basically loop through every single waypoint inside of 95 00:06:28,260 --> 00:06:31,530 this table and path, find towards that particular waypoint. 96 00:06:32,400 --> 00:06:35,910 The first thing we want to check is the action for this waypoint. 97 00:06:35,910 --> 00:06:40,860 So for example, if this waypoint is at a higher position in our AI needs to jump for that, well we 98 00:06:40,860 --> 00:06:41,760 can go ahead and check. 99 00:06:41,760 --> 00:06:43,890 So if this waypoint. 100 00:06:44,870 --> 00:06:46,490 Dot action. 101 00:06:46,730 --> 00:06:50,750 And actually we can go ahead and denote this as a path waypoint. 102 00:06:51,380 --> 00:06:59,150 So if this waypoint dot action, the action to perform with this waypoint is equal to the enum dot path 103 00:06:59,150 --> 00:07:01,430 waypoint action dot jump. 104 00:07:01,430 --> 00:07:07,490 So if we need to jump to get to this waypoint, then we can refer to my humanoid and set jump equal 105 00:07:07,490 --> 00:07:08,240 to true. 106 00:07:08,390 --> 00:07:13,460 And then from this point we're going to refer to my humanoid again and use the move two function. 107 00:07:13,460 --> 00:07:16,430 And we want to move to this waypoints position. 108 00:07:16,430 --> 00:07:18,800 So waypoint dot position. 109 00:07:19,340 --> 00:07:24,890 And then from this point, we can use our wait for event function and wait for our my humanoid dot move 110 00:07:24,890 --> 00:07:25,820 to finish. 111 00:07:25,820 --> 00:07:29,600 So that way we actually know that we successfully moved to this waypoint. 112 00:07:29,600 --> 00:07:32,360 And then of course we're going to have a timeout. 113 00:07:33,540 --> 00:07:39,810 So if for some reason we timed out, then again it could mean that our AI is stuck. 114 00:07:39,810 --> 00:07:42,120 So we're going to check if we timed out. 115 00:07:42,120 --> 00:07:47,280 If that's the case, then we can print out a warning and say something like our squid word. 116 00:07:48,360 --> 00:07:56,130 I, uh, timed out when path finding to player. 117 00:07:56,250 --> 00:07:58,110 Is it stuck? 118 00:07:58,110 --> 00:07:59,700 We could say something like that. 119 00:07:59,910 --> 00:08:06,540 And we're going to refer to my humanoid set jump equal to true to try to get our AI unstuck. 120 00:08:06,540 --> 00:08:09,990 And then we're going to break basically out of this for loop. 121 00:08:10,780 --> 00:08:14,740 Another thing we want to check is whether or not our AI can directly see our player. 122 00:08:14,740 --> 00:08:21,400 So if not, check visibility and we pass, um, the target. 123 00:08:21,640 --> 00:08:28,030 So if we cannot see this player, then we're just going to continue looping. 124 00:08:28,030 --> 00:08:32,740 Or basically we're just going to continue pathfinding along these waypoints. 125 00:08:32,740 --> 00:08:34,150 If we cannot see the player. 126 00:08:34,150 --> 00:08:37,930 However, if we can see the player, then there's no need to pathfind. 127 00:08:37,930 --> 00:08:41,380 And instead what we could do is run directly towards our player. 128 00:08:42,190 --> 00:08:47,350 So what we're going to do is we're going to first get this player by referring to the player service 129 00:08:47,350 --> 00:08:51,340 and use the function get player from character and pass our target dot parent. 130 00:08:52,610 --> 00:08:57,440 Now we also want to go ahead and create a variable to refer to the last position of the player, just 131 00:08:57,440 --> 00:08:59,720 in case the player gets out of our sight. 132 00:08:59,720 --> 00:09:04,970 So if the player, you know moves around a corner and disappears out of our sight, then we can have 133 00:09:04,970 --> 00:09:08,540 the AI run or walk to the last position that they were seen at. 134 00:09:08,540 --> 00:09:11,300 So we'll refer to the target dot position. 135 00:09:12,060 --> 00:09:16,980 And basically as long as we can see this player, then we can just run directly towards them. 136 00:09:16,980 --> 00:09:19,050 So we're going to have a repeat loop here. 137 00:09:19,050 --> 00:09:24,510 And now we're going to do is update our last position equal to the target dot position. 138 00:09:24,510 --> 00:09:30,330 And we're going to use my humanoid and use the move two function and pass the last position. 139 00:09:30,330 --> 00:09:34,050 So we're going to have our humanoid constantly running towards our player. 140 00:09:34,050 --> 00:09:38,250 And at the same time we're also going to try and attack our player as well. 141 00:09:38,250 --> 00:09:45,330 So we can have a function called attack and pass our target to it to try to get our AI to attack or 142 00:09:45,330 --> 00:09:46,650 jump scare our player. 143 00:09:46,650 --> 00:09:53,190 So we could create another function up here called attack, which will get our target, and we'll fill 144 00:09:53,190 --> 00:09:53,730 this out. 145 00:09:53,730 --> 00:09:55,020 Just a moment. 146 00:09:56,200 --> 00:10:02,350 But after that, to what we could do is we could check, um, let's say our player dies or for some 147 00:10:02,350 --> 00:10:04,840 reason, our player's character gets destroyed. 148 00:10:04,840 --> 00:10:11,080 So if target dot parent is equal to nil for some reason, which means they got destroyed, then we're 149 00:10:11,080 --> 00:10:13,180 just going to break out of this repeat loop. 150 00:10:13,270 --> 00:10:17,110 Otherwise we're just going to yield for point let's say zero five seconds. 151 00:10:17,290 --> 00:10:20,830 So we're going to continue running towards our player. 152 00:10:20,830 --> 00:10:28,690 And we're going to keep trying to attack them until either they are no longer visible or we are no longer 153 00:10:28,690 --> 00:10:32,230 active, or the player is dead or they're inside of a locker or whatever. 154 00:10:32,230 --> 00:10:36,940 So until not, let's say check visibility of this target. 155 00:10:36,940 --> 00:10:41,380 So if we can no longer see them, then we want to break out of this repeat loop. 156 00:10:41,590 --> 00:10:51,010 Or if we are no longer active or our AI has been stopped, or let's say our target dot parent dot humanoid 157 00:10:51,010 --> 00:10:55,450 dot health becomes less than one, which means the player died. 158 00:10:55,450 --> 00:10:58,630 Then we don't want to, you know, continue chasing after them. 159 00:10:59,610 --> 00:11:07,140 Um, another thing we could check is, let's say the player get attribute inside locker is true. 160 00:11:07,140 --> 00:11:09,990 So let's say they hop inside of a locker while we're tracing them. 161 00:11:09,990 --> 00:11:11,850 Well, we don't want to chase them anymore. 162 00:11:12,450 --> 00:11:15,480 Or we can check if the player get attribute. 163 00:11:15,480 --> 00:11:17,160 Let's say they have escaped. 164 00:11:17,160 --> 00:11:19,020 So escaped. 165 00:11:20,040 --> 00:11:24,900 So basically, after we have lost sight of this player or the player has gone inside of the locker, 166 00:11:24,900 --> 00:11:31,080 then what we want to do is we want to either move our humanoid to the last position that our player 167 00:11:31,080 --> 00:11:37,230 was seen at, or we want to move our AI to a new player that is visible. 168 00:11:37,230 --> 00:11:42,210 So, for example, let's say right when we lose visibility of this player, we can actually see another 169 00:11:42,210 --> 00:11:42,870 player. 170 00:11:42,870 --> 00:11:45,840 We want to go ahead and start chasing that player instead. 171 00:11:45,840 --> 00:11:51,720 So what we could do is we could check if there is a nearest visible player. 172 00:11:51,720 --> 00:11:56,610 So if get nearest visible player returns something back to us, then we're just going to completely 173 00:11:56,610 --> 00:12:03,210 break out of this for loop, which allows us to exit out of our new path to function, and which we'll 174 00:12:03,210 --> 00:12:09,060 go back into our while loop and it'll get us a new target, and then we start chasing that player instead. 175 00:12:09,730 --> 00:12:13,990 So we break out if we see another player, but if we don't see. 176 00:12:14,710 --> 00:12:21,820 Another player, then what we could do is just refer to our humanoid and move him to the last position 177 00:12:21,820 --> 00:12:25,720 that we saw this player at, and we'll just wait for this event. 178 00:12:25,720 --> 00:12:28,630 So my humanoid move to finished. 179 00:12:29,320 --> 00:12:32,140 And we can have a timeout of like three seconds. 180 00:12:32,590 --> 00:12:39,610 So this function right here should allow us to either pathfind towards players after we create some 181 00:12:39,610 --> 00:12:46,630 waypoints to them, or if we see that player directly, then we can just repeatedly run towards that 182 00:12:46,630 --> 00:12:52,000 player and try to attack them until we can no longer see them or they're inside of a locker or whatever. 183 00:12:52,000 --> 00:12:56,230 So actually what we could do is go ahead and fill out our attack function. 184 00:12:56,620 --> 00:13:01,060 We can go ahead and scroll up and inside of our attack function, the first thing we want to make sure 185 00:13:01,060 --> 00:13:02,740 is that we can actually attack. 186 00:13:02,740 --> 00:13:06,370 So if we cannot attack, then we're just going to return out of this function. 187 00:13:06,790 --> 00:13:11,350 Another thing we want to check is whether or not this target is actually a player. 188 00:13:11,350 --> 00:13:13,540 So we're going to use players. 189 00:13:14,090 --> 00:13:15,680 Get player from character and past. 190 00:13:15,680 --> 00:13:16,040 Target. 191 00:13:16,250 --> 00:13:17,060 Parent. 192 00:13:17,640 --> 00:13:20,700 So for some reason this is not a player. 193 00:13:20,700 --> 00:13:24,210 So if not player then we're just going to return as well. 194 00:13:25,080 --> 00:13:31,050 Another thing we want to check is if this player is inside of a locker or they have escaped, or let's 195 00:13:31,050 --> 00:13:32,310 say they've already been jumpscared. 196 00:13:32,340 --> 00:13:33,600 Then we want to ignore this player. 197 00:13:33,600 --> 00:13:42,810 So if player get attribute inside locker or player get attribute escaped, or what we could do is we 198 00:13:42,810 --> 00:13:45,060 could set another attribute on this player. 199 00:13:45,060 --> 00:13:48,750 So if player get attribute we could call it something like jumpscare. 200 00:13:48,750 --> 00:13:51,630 So if that's true then we're just going to return as well. 201 00:13:51,630 --> 00:13:56,220 So when we jumpscare our players we're going to set an attribute on them of jumpscare. 202 00:13:56,220 --> 00:14:00,570 And we can set that equal to true to signify that this player has already been jumpscared. 203 00:14:01,350 --> 00:14:07,080 Another thing we want to check is if this player team for some reason is on the, uh, dead team. 204 00:14:07,800 --> 00:14:10,680 So if this player is dead, then we don't care about them either. 205 00:14:10,680 --> 00:14:12,060 We're going to return. 206 00:14:12,390 --> 00:14:18,030 Um, another thing we want to check is whether or not this player is within, like, an attack range. 207 00:14:18,030 --> 00:14:21,510 So we can go ahead and define that as well within our properties table. 208 00:14:22,020 --> 00:14:29,130 So up here we can go up and we can create something like uh we could call it attack range. 209 00:14:29,130 --> 00:14:31,410 So what we'll do here. 210 00:14:32,850 --> 00:14:36,030 Here's I'll create something called attack range. 211 00:14:36,840 --> 00:14:40,350 And that's going to be equal to we could do something like within four studs. 212 00:14:40,350 --> 00:14:44,850 So if a player is within four studs of our AI then they can get jump scared. 213 00:14:45,450 --> 00:14:54,570 So we'll go back and we'll check if my root part dot position subtracted by the target dot position 214 00:14:54,570 --> 00:14:56,310 get the magnitude of that. 215 00:14:56,310 --> 00:15:01,920 If that's greater than I properties dot attack range, then we're just going to ignore this player. 216 00:15:02,570 --> 00:15:09,980 And another thing we want to check is if the target parent for some reason is equal to nil, which means 217 00:15:09,980 --> 00:15:11,180 somehow this was destroyed. 218 00:15:11,180 --> 00:15:12,440 So we're going to return as well. 219 00:15:12,470 --> 00:15:16,790 Basically, these are just a whole bunch of different fail safes just to make sure we don't get any 220 00:15:16,790 --> 00:15:17,540 errors. 221 00:15:17,630 --> 00:15:22,220 Otherwise if everything checks out then we can set Kanatak equal to false. 222 00:15:22,880 --> 00:15:27,890 And we're going to set on this player the attribute of jump scare and set that equal to true. 223 00:15:28,400 --> 00:15:34,280 Then we can use our manipulate camera, event and fire to this particular player that we want them to 224 00:15:34,280 --> 00:15:35,030 jump scare. 225 00:15:35,030 --> 00:15:37,820 So we could do player camera manipulation. 226 00:15:37,820 --> 00:15:40,340 Enum dot two client dot jump scare. 227 00:15:41,310 --> 00:15:47,310 And then from this point, uh, we'll just move the player C frame back inside of, like, the spawn. 228 00:15:47,310 --> 00:15:52,350 So we could do player dot character dot humanoid route part. 229 00:15:53,420 --> 00:15:56,900 Get the keyframe and set that equal to inside of the workspace. 230 00:15:57,080 --> 00:16:02,600 Inside of the filtering folder, there's a part in there called teleport Part and spawn, and we'll 231 00:16:02,600 --> 00:16:09,500 just set the player's, uh, keyframe equal to this keyframe, and then we'll set the team of our player 232 00:16:09,500 --> 00:16:13,580 equal to the dead team, because, I mean, they're getting jumpscares, they're dead. 233 00:16:14,180 --> 00:16:20,480 And then after this, we'll have a function be delayed for two seconds, because what we're going to 234 00:16:20,480 --> 00:16:26,960 do is we're going to use our update guy event and fire to this particular player to tell them that they 235 00:16:26,960 --> 00:16:27,650 died. 236 00:16:27,650 --> 00:16:32,030 So we don't want to tell them that they died immediately, because that will fade the death screen on 237 00:16:32,030 --> 00:16:33,470 their screen right away. 238 00:16:33,470 --> 00:16:35,900 But instead we want to wait two seconds. 239 00:16:35,900 --> 00:16:40,040 That way the player actually has enough time to display the jumpscare on their screen. 240 00:16:40,040 --> 00:16:44,810 That way they get spooked, and then after two seconds, we're going to tell this player, uh, that 241 00:16:44,810 --> 00:16:47,600 they died so we could do GUI actions. 242 00:16:47,600 --> 00:16:55,100 Enum Dot died and then we'll set on this player jumpscare back to false. 243 00:16:55,830 --> 00:17:00,120 That way they can be jumpscared again in the future in case the player decides to respawn back into 244 00:17:00,120 --> 00:17:00,720 the map. 245 00:17:01,570 --> 00:17:07,870 And then finally we can have another delayed function to go ahead and reset the can attack variable 246 00:17:07,870 --> 00:17:08,740 back to true. 247 00:17:09,400 --> 00:17:12,580 So that means we can have another property inside of here. 248 00:17:12,580 --> 00:17:20,230 We could call it like cooldown between attack, and I'll just set it to something like, uh, I don't 249 00:17:20,230 --> 00:17:21,250 know, 1.5 seconds. 250 00:17:21,250 --> 00:17:22,300 That's probably good. 251 00:17:23,500 --> 00:17:31,360 So we'll delay a function from running for our AI properties dot cooldown between attacks. 252 00:17:31,360 --> 00:17:38,260 So after 1.5 seconds is up, then we can go ahead and set can attack back equal to true. 253 00:17:38,290 --> 00:17:41,740 That way our AI is able to attack another player again. 254 00:17:42,190 --> 00:17:42,520 All right. 255 00:17:42,520 --> 00:17:42,850 Perfect. 256 00:17:42,850 --> 00:17:44,890 So everything's looking pretty good here so far. 257 00:17:44,890 --> 00:17:50,380 I think the next thing we can go ahead and fill out is the functionality to fulfill when we actually 258 00:17:50,380 --> 00:17:53,020 get told to be jumpscared. 259 00:17:53,020 --> 00:17:56,650 So on the client and our camera manipulation handler. 260 00:17:57,270 --> 00:17:59,670 When we get given the action of jump scare. 261 00:17:59,670 --> 00:18:01,950 Currently we have nothing inside of here. 262 00:18:01,950 --> 00:18:07,500 But my plan is is we're going to use our jump scares module script, and we can have a section in here 263 00:18:07,500 --> 00:18:12,240 that stores a bunch of different functions for jump scaring the player, and we can just pick one of 264 00:18:12,240 --> 00:18:15,030 those functions randomly if you would like. 265 00:18:15,030 --> 00:18:18,690 You could have multiple different types of jump scares and pick one randomly and the jump scare the 266 00:18:18,690 --> 00:18:19,380 player with that. 267 00:18:19,830 --> 00:18:23,850 So inside of our jump scares module script, we could create a key. 268 00:18:23,850 --> 00:18:27,210 I'll call it all jump scares and it could be equal to a table. 269 00:18:27,210 --> 00:18:30,180 And inside of here you could just store a whole bunch of different functions. 270 00:18:30,180 --> 00:18:32,490 I'll just create a lambda function in here. 271 00:18:32,610 --> 00:18:38,250 And all this is going to do is basically just, um, refer to our jump scare model that is inside of 272 00:18:38,250 --> 00:18:39,060 replicated storage. 273 00:18:39,060 --> 00:18:45,660 Set that in the map, we would move the player's camera onto the part that's inside of that jump scare 274 00:18:45,660 --> 00:18:49,050 model, jump scare the player and then you know that's that. 275 00:18:49,050 --> 00:18:52,770 So inside of here, what we could do is refer to a few services. 276 00:18:52,770 --> 00:18:54,810 One we'll need is replicated storage. 277 00:18:57,060 --> 00:18:59,580 And we're also going to need the sound service. 278 00:19:03,430 --> 00:19:07,390 In this point, we can go ahead and make a quick reference to the current camera. 279 00:19:07,390 --> 00:19:09,490 So that's in workspace dot current camera. 280 00:19:09,700 --> 00:19:15,910 And we could also go ahead and make a reference to the jump scare model which is in replicated storage 281 00:19:16,030 --> 00:19:17,080 instances. 282 00:19:17,080 --> 00:19:19,990 And we get the jump scare model inside of there. 283 00:19:20,880 --> 00:19:22,080 From this point. 284 00:19:22,080 --> 00:19:27,180 When this function gets called, what we could do is we would first get the original field of view of 285 00:19:27,180 --> 00:19:27,750 our camera. 286 00:19:27,750 --> 00:19:33,300 So current cam field of view, because I kind of want to shrink the field of view to make it zoomed 287 00:19:33,300 --> 00:19:36,600 in on, uh, our squidward's face. 288 00:19:36,900 --> 00:19:42,180 But basically it will refer to our jump scare model, set the parent of that equal to the workspace, 289 00:19:42,720 --> 00:19:48,480 and then refer to our current camera and set the camera type equal to enum dot camera type dot scriptable. 290 00:19:48,970 --> 00:19:54,820 And then set the current camera field of view, and I found a value of 40 to be pretty good. 291 00:19:55,270 --> 00:20:00,730 And then we're going to refer to our current camera's C frame and update that equal to the jump scare 292 00:20:00,730 --> 00:20:01,390 model. 293 00:20:01,390 --> 00:20:03,730 And inside of there there's a camera part. 294 00:20:03,730 --> 00:20:06,970 And we want to set our player C frame equal to that part. 295 00:20:08,290 --> 00:20:10,240 So in fact, if we actually. 296 00:20:10,990 --> 00:20:13,840 Let me close out all this and go into replicated storage. 297 00:20:13,840 --> 00:20:16,750 We have a jump scare model inside of the instances folder. 298 00:20:16,750 --> 00:20:18,880 We put that in the workspace and go to that. 299 00:20:19,680 --> 00:20:21,450 Uh, here's our jump scare model. 300 00:20:21,480 --> 00:20:25,290 We have an invisible part right here, which is our camera part that we're going to set the player's 301 00:20:25,290 --> 00:20:29,250 camera, see frame to, to look directly into the face of our Squidward. 302 00:20:29,250 --> 00:20:34,200 And then from this point, we can play some wacky animation and play a loud sound to jump scare our 303 00:20:34,200 --> 00:20:34,800 player. 304 00:20:35,010 --> 00:20:40,410 So let me go ahead and move this guy back inside of the instances folder. 305 00:20:41,380 --> 00:20:47,560 Because what we can do from this point is we can get the animation track from our jump scare model. 306 00:20:47,560 --> 00:20:52,600 So remember when we originally set up our game, you had that animation inside of the jump scare model 307 00:20:52,600 --> 00:20:55,480 that you set up for the AI squid, where that's in there. 308 00:20:55,840 --> 00:20:59,200 Um, if you haven't done that yet, then go ahead and do that real quick. 309 00:20:59,200 --> 00:21:04,210 Just open up your animation editor and edit the animation for your squid word. 310 00:21:04,210 --> 00:21:07,030 Create some kind of neat little custom jump scare animation. 311 00:21:07,030 --> 00:21:12,730 I've already created one and put my ID in there, so I'm going to get the track by referring to the 312 00:21:12,730 --> 00:21:13,870 jump scare model. 313 00:21:15,080 --> 00:21:15,710 Dot. 314 00:21:15,710 --> 00:21:19,340 Get the Squidward that's in there, get his humanoid and get the animator, and we're going to load 315 00:21:19,340 --> 00:21:25,790 the animation jumpscare model dot Squidward dot jumpscare animations and get jumpscare number one. 316 00:21:26,570 --> 00:21:33,230 And then we can play this track and at the same time, inside of the sound service SFX, there's a folder 317 00:21:33,230 --> 00:21:38,030 called jumpscare, and there's a sound in there called jumpscare one, and we're going to play that 318 00:21:38,030 --> 00:21:41,270 sound, and I'll demonstrate that sound real quick for you. 319 00:21:41,270 --> 00:21:46,340 So we go to the sound service SFX jumpscare jumpscare one we play this. 320 00:21:49,440 --> 00:21:54,750 It's very, very loud and it'll surely knock the socks off of anyone who hears it. 321 00:21:54,750 --> 00:22:01,320 So after that plays, what we're going to do is we're going to wait for that sound to finish playing. 322 00:22:03,060 --> 00:22:08,280 And after that is done, then what we could do is we could set the current camera field of view back 323 00:22:08,280 --> 00:22:10,020 to the original field of view. 324 00:22:10,020 --> 00:22:18,000 And we're also going to stop the animation track from playing and put our jump scare model parent back 325 00:22:18,000 --> 00:22:21,270 into replicated storage instances. 326 00:22:21,780 --> 00:22:27,960 And the reason we're not resetting our camera from here is because when our player dies, then when 327 00:22:27,960 --> 00:22:33,240 we start to enable the spectating system, that spectating system is going to handle, resetting the 328 00:22:33,240 --> 00:22:40,440 player's camera and placing it on the map onto whatever players are left that are alive and stuff like 329 00:22:40,440 --> 00:22:40,710 that. 330 00:22:40,710 --> 00:22:44,400 So we don't have to worry about controlling or resetting the camera from here. 331 00:22:44,400 --> 00:22:47,250 But here is our very basic jump scare function. 332 00:22:47,730 --> 00:22:52,950 And from this point, what we could do inside of our camera manipulation handler is we've already, 333 00:22:52,950 --> 00:22:53,400 I believe. 334 00:22:53,400 --> 00:22:55,710 Yeah, we've already required our jump scare module. 335 00:22:55,710 --> 00:22:59,130 So what we could do from this point is refer to our jump scare module. 336 00:22:59,650 --> 00:23:02,740 And get the all jump scares table. 337 00:23:02,740 --> 00:23:09,100 And inside of here we can pick out a random jump scare and we'll use RNG next integer. 338 00:23:09,960 --> 00:23:17,730 And pick a value starting at one to the number of functions that are inside of our all jumpscares table. 339 00:23:18,270 --> 00:23:23,400 And then to actually call this function, we're just going to put the two parentheses at the very end, 340 00:23:23,400 --> 00:23:27,210 which allows us to execute the functionality for our jumpscare. 341 00:23:27,210 --> 00:23:28,110 And that's it. 342 00:23:28,110 --> 00:23:34,050 So now any time we get told to be jumpscared, we should get this jumpscare played on our screen. 343 00:23:34,050 --> 00:23:34,740 Perfect. 344 00:23:35,160 --> 00:23:38,970 All right, so back inside of our AI squid order handler, the next thing we can go ahead and figure 345 00:23:38,970 --> 00:23:41,910 out is what we want to do when we do not have a target. 346 00:23:41,910 --> 00:23:45,390 Well, what we want to do is we want to wander around the map, right? 347 00:23:45,390 --> 00:23:51,510 But we only want to wander around the map if we haven't exceeded those wandering iterations I was talking 348 00:23:51,510 --> 00:23:51,870 about. 349 00:23:51,870 --> 00:23:57,900 So we want to keep track of how many times our AI has been wandering around the map to different points. 350 00:23:57,900 --> 00:24:03,720 And if our AI has wandered around the map to too many different points, then we want to respawn our 351 00:24:03,720 --> 00:24:04,500 Squidward. 352 00:24:04,500 --> 00:24:09,840 So when we do get a target, we could reset our wandering iterations back to zero. 353 00:24:10,110 --> 00:24:14,880 Otherwise, what we want to do is we want to check if our wandering iterations is below a particular 354 00:24:14,880 --> 00:24:15,570 threshold. 355 00:24:15,570 --> 00:24:19,860 So again, inside of our properties table we could create a new value in here. 356 00:24:19,860 --> 00:24:23,970 We could call it something like max wandering iterations. 357 00:24:23,970 --> 00:24:27,990 And we could set this to something like uh, maybe five. 358 00:24:27,990 --> 00:24:29,430 I think five would be good. 359 00:24:29,430 --> 00:24:32,070 Of course you can adjust this value to whatever you like. 360 00:24:33,510 --> 00:24:38,040 So far, wandering iterations becomes greater than or equal to our AI properties. 361 00:24:38,220 --> 00:24:39,840 Max wandering iterations. 362 00:24:39,840 --> 00:24:45,510 Then that means we have not seen any other players because our wandering iterations hasn't been reset 363 00:24:45,510 --> 00:24:48,120 and we've been wandering around the map for way too long. 364 00:24:48,120 --> 00:24:53,370 So what we could do is we could set wandering iterations back to zero and use our disappear and spawn 365 00:24:53,370 --> 00:25:00,150 a new location function to have our AI, you know, disappear and spawn at a new location to try to 366 00:25:00,150 --> 00:25:03,630 find new players to attack otherwise. 367 00:25:04,180 --> 00:25:09,550 If we don't have a target and we haven't exceeded the wandering iterations threshold, then we can go 368 00:25:09,550 --> 00:25:11,650 ahead and just randomly wander around the map. 369 00:25:11,650 --> 00:25:16,300 So the first thing we would want to do is we would want to refer to my humanoid walk speed and set that 370 00:25:16,300 --> 00:25:18,910 equal to the AI properties dot wander speed. 371 00:25:18,910 --> 00:25:25,180 So that way our AI is just casually wandering around the map, and we would want to set wandering iterations 372 00:25:25,180 --> 00:25:32,260 plus equal one, and we would want to create a function we could call it like wander to have our, uh, 373 00:25:32,260 --> 00:25:35,470 you know, I wander from point to point on our map. 374 00:25:35,470 --> 00:25:37,540 So let's actually go ahead and create that real quick. 375 00:25:37,540 --> 00:25:39,880 We can create a function, we'll call it wander. 376 00:25:40,620 --> 00:25:41,430 And inside of here. 377 00:25:41,430 --> 00:25:45,180 What we would want to do is we would want to create a variable called goal. 378 00:25:45,180 --> 00:25:50,040 And this would represent the part on the map that we would want to pathfind towards. 379 00:25:50,040 --> 00:25:56,910 So that means we would have to create a function to basically get the nearest waypoint to our Squidward. 380 00:25:56,910 --> 00:26:03,660 So that means we'll create another function and we can call this function get nearest waypoint. 381 00:26:05,010 --> 00:26:07,080 And we could have this return back to us. 382 00:26:07,110 --> 00:26:12,870 A part that is the closest to our Squidward that we need to wander to. 383 00:26:12,900 --> 00:26:16,260 So we could call this get nearest waypoint. 384 00:26:18,540 --> 00:26:23,970 And since this would return back to us a part, we could get the position of that part and store it 385 00:26:23,970 --> 00:26:26,340 within our goal variable here. 386 00:26:27,650 --> 00:26:33,890 So what we want to do is instead of get nearest waypoint, we want to make sure we give our eye Squidward, 387 00:26:33,890 --> 00:26:37,070 a waypoint that they haven't passed around to yet. 388 00:26:37,190 --> 00:26:44,630 So the first thing I want to verify is if the number of elements in our points already visited table 389 00:26:44,630 --> 00:26:48,320 is equal to the number of walk to points that we have on the map. 390 00:26:48,320 --> 00:26:54,620 So this signifies that our eye Squidward has already visited or path found to every single point on 391 00:26:54,620 --> 00:26:54,920 the map. 392 00:26:54,920 --> 00:27:01,160 If that's the case, then we need to reset our points already visited table by clearing out all the 393 00:27:01,160 --> 00:27:02,360 values inside of there. 394 00:27:02,690 --> 00:27:07,070 Otherwise, we're basically going to do the same thing that we did for the Get nearest visible player. 395 00:27:07,070 --> 00:27:10,490 We'll have a variable, we'll call it closest Point. 396 00:27:11,320 --> 00:27:13,630 We're not going to initialize it to anything just yet. 397 00:27:13,810 --> 00:27:20,770 And we're also going to have a last distance to calculate or basically compare, you know, the last 398 00:27:20,770 --> 00:27:22,270 distance to the closest point. 399 00:27:22,270 --> 00:27:25,210 And we're going to just set this to some randomly high value. 400 00:27:25,450 --> 00:27:31,030 And then we're going to loop through every single point and walk two points. 401 00:27:31,030 --> 00:27:35,380 And what we could do is we first want to make sure that we haven't visited this point. 402 00:27:35,380 --> 00:27:41,620 So if we find inside of our points already visited table this particular point, then we're just going 403 00:27:41,620 --> 00:27:42,970 to continue looping. 404 00:27:44,060 --> 00:27:49,610 Otherwise, we're going to calculate the distance from my root part dot position. 405 00:27:49,610 --> 00:27:52,370 Subtract this by this point's position. 406 00:27:53,280 --> 00:27:54,960 And get the magnitude of that. 407 00:27:55,140 --> 00:28:03,870 If this distance is, let's say, less than the last distance that we created up here, then we can 408 00:28:03,870 --> 00:28:12,150 go ahead and set closest point equal to this new point, and then set last distance equal to the distance 409 00:28:12,150 --> 00:28:13,200 we just calculated. 410 00:28:13,200 --> 00:28:19,080 So this way we are looping through all the points and going through the process of elimination to find 411 00:28:19,080 --> 00:28:20,610 the absolute closest point. 412 00:28:20,610 --> 00:28:25,650 And then once we do that we can go ahead and return this closest point. 413 00:28:25,650 --> 00:28:32,190 And we could also insert this point into our points already visited table to signify that this point 414 00:28:32,190 --> 00:28:33,960 we have already passed found towards. 415 00:28:34,530 --> 00:28:39,930 So from this point we get the goal that we want to pathfind towards, and then we're going to use the 416 00:28:39,930 --> 00:28:42,420 path find service again to get a path. 417 00:28:42,870 --> 00:28:46,680 So we'll use pathfinding create path. 418 00:28:46,680 --> 00:28:50,040 Again we're going to pass the eye properties dot agent parameters. 419 00:28:50,610 --> 00:28:57,120 And then we're going to use the path to compute starting at my root part dot position to this new goal 420 00:28:57,120 --> 00:29:00,450 that we just got from our get nearest waypoint function. 421 00:29:00,810 --> 00:29:09,180 Now if the path dot status is not equal to the enum dot path status dot success, then we need to print 422 00:29:09,180 --> 00:29:19,620 out again or put a warning that our Squidward I was unable to calculate wander path to this particular 423 00:29:19,620 --> 00:29:20,130 point. 424 00:29:20,130 --> 00:29:26,610 Right from that point, what we would do is we could clear out all of the points inside of our points 425 00:29:26,610 --> 00:29:27,990 already visited table. 426 00:29:28,380 --> 00:29:34,080 We'll set wandering iterations to zero, and what we could do is just disappear and spawn at a new location 427 00:29:34,080 --> 00:29:37,350 and try again, and then we'll just return out of this function. 428 00:29:38,000 --> 00:29:38,450 Otherwise. 429 00:29:38,450 --> 00:29:43,340 If we were successful, then again, we're going to get all of the waypoints using path. 430 00:29:43,340 --> 00:29:44,630 Get waypoints. 431 00:29:45,670 --> 00:29:48,250 And we're going to loop through every single waypoint. 432 00:29:48,250 --> 00:29:52,960 So that's a path a waypoint inside of our waypoints table. 433 00:29:53,530 --> 00:29:59,710 And all we're going to do is we're going to first check if the waypoint dot action is equal to the enum 434 00:29:59,710 --> 00:30:02,920 dot path waypoint action dot jump. 435 00:30:02,920 --> 00:30:05,410 If it is then we're going to have our humanoid jump. 436 00:30:08,250 --> 00:30:14,820 Otherwise, we're going to do my humanoid move two and move him to this waypoint position. 437 00:30:16,290 --> 00:30:17,520 An accident would capitalize that. 438 00:30:17,520 --> 00:30:18,240 My bad. 439 00:30:19,230 --> 00:30:23,580 And then again, we're going to use our weight for event function and weight for the My Humanoid dot 440 00:30:23,580 --> 00:30:26,820 move to finish and have a timeout of like three seconds. 441 00:30:27,540 --> 00:30:29,340 And we can check if we timed out. 442 00:30:30,380 --> 00:30:38,120 So if we timed out, then we can print something like, uh, Squidward, I. 443 00:30:39,270 --> 00:30:41,460 Timed out during a wander. 444 00:30:41,460 --> 00:30:42,780 Something like that. 445 00:30:42,930 --> 00:30:46,170 We'll do my humanoid jump equal to true just in case. 446 00:30:46,170 --> 00:30:50,880 For some reason, our AI is stuck, and then we're just going to break out of our for loop. 447 00:30:51,210 --> 00:30:56,310 Otherwise, another thing we want to check is while we are wandering around the map, is whether or 448 00:30:56,310 --> 00:30:59,280 not we have a visible player. 449 00:30:59,280 --> 00:31:05,130 So we're going to get a target and we're going to do get nearest visible player. 450 00:31:05,700 --> 00:31:12,720 And if we have a target, then we want to return that target from this function back to our main function. 451 00:31:12,720 --> 00:31:15,270 So we could get a variable. 452 00:31:15,270 --> 00:31:19,020 We'll call it target scene while wandering. 453 00:31:19,600 --> 00:31:23,500 So this will either be nil or will actually get returned back to us. 454 00:31:23,500 --> 00:31:25,240 A target to chase after. 455 00:31:25,570 --> 00:31:31,000 So if we see a target while we are wandering around the map, then we're going to return that target. 456 00:31:31,360 --> 00:31:37,780 Otherwise, if we break out of this for loop or we finished pathfinding to this particular goal point 457 00:31:37,780 --> 00:31:43,480 here without seeing any players, then what I want to do is I want to go ahead and like wait for a little 458 00:31:43,480 --> 00:31:43,720 bit. 459 00:31:43,720 --> 00:31:49,510 I just want to have our AI stand still and not instantly pathfind to the next waypoint. 460 00:31:49,510 --> 00:31:54,670 That way, you know, um, he's not constantly moving all the time and it looks a little bit more natural. 461 00:31:54,670 --> 00:32:00,280 What I could do is I could just have a wait, uh, statement here and just wait a random amount of time. 462 00:32:00,280 --> 00:32:08,350 But the problem with doing this is that if a player somehow were to walk in front of our AI while they 463 00:32:08,350 --> 00:32:13,300 were wandering and this wait statement is going on, our AI is going to be stuck just sitting there 464 00:32:13,300 --> 00:32:14,590 doing nothing. 465 00:32:14,590 --> 00:32:19,360 So to avoid that, what we could do is we could have a for loop and we could start it at an index of 466 00:32:19,360 --> 00:32:24,880 one and use RNG next integer and pick a random number between like four and 16. 467 00:32:24,880 --> 00:32:29,320 Because what we're going to do is we're going to yield for like 0.25 seconds. 468 00:32:29,320 --> 00:32:35,140 So that way every 0.25 seconds our AI will actually check if there's any players in front of it. 469 00:32:35,140 --> 00:32:38,680 So what we could do is we could check to see if we have a target. 470 00:32:38,680 --> 00:32:41,500 And actually we'll just copy exactly what we did right here. 471 00:32:41,500 --> 00:32:45,460 So we'll just sit here and yield, have our AI stand still for a little bit. 472 00:32:45,730 --> 00:32:52,420 And while our AI is standing still every 0.25 seconds, it's going to check whether or not there is 473 00:32:52,420 --> 00:32:53,830 a nearest visible player. 474 00:32:53,830 --> 00:33:00,070 If it is, it's going to return that target back out of our wander function, and then we can get that 475 00:33:00,070 --> 00:33:00,820 target. 476 00:33:00,820 --> 00:33:04,510 And what we could do is we could check if there was a target seen while wandering. 477 00:33:04,510 --> 00:33:09,430 If that's the case, then we're just basically going to do the exact same thing that we did up here. 478 00:33:09,430 --> 00:33:15,940 We're just going to copy this, paste that in here and we're going to pass target seen a while wandering. 479 00:33:16,450 --> 00:33:20,590 Now the last important thing that we need to do in this while loop is we need to yield. 480 00:33:20,590 --> 00:33:20,950 Okay. 481 00:33:20,950 --> 00:33:23,230 We don't want to be flying through this while loop. 482 00:33:23,230 --> 00:33:27,430 So we want to, uh, basically have a yield statement down here. 483 00:33:27,430 --> 00:33:29,380 And we could do something like 0.1 seconds. 484 00:33:29,380 --> 00:33:34,840 So every 0.1 seconds this is looping running through the different functions, checking to see if there's 485 00:33:34,840 --> 00:33:36,580 any nearest visible players. 486 00:33:36,580 --> 00:33:41,770 If there's a target um it'll check the wandering iterations to make sure that we're not wandering too 487 00:33:41,770 --> 00:33:42,010 much. 488 00:33:42,010 --> 00:33:44,920 And if we are, we'll disappear and spawn at a new location. 489 00:33:44,920 --> 00:33:50,050 It'll check to see if we have a target while we're wandering, or if we just see a target. 490 00:33:50,050 --> 00:33:55,150 Then we'll just chase directly after them and try to attack and jump scare them all that kind of good 491 00:33:55,150 --> 00:33:55,990 stuff. 492 00:33:56,320 --> 00:33:56,680 All right? 493 00:33:56,680 --> 00:34:00,940 Otherwise, uh, another few things we can go ahead and fill out real quick is our stop AI function. 494 00:34:00,940 --> 00:34:02,080 This one is going to be really easy. 495 00:34:02,080 --> 00:34:06,490 All we're going to do is just set active equal to false when we want to stop our AI. 496 00:34:06,880 --> 00:34:13,210 And when we do stop our AI, we could put down a warning message down here like, um, we could say 497 00:34:13,210 --> 00:34:15,970 something like AI is no longer active. 498 00:34:16,540 --> 00:34:22,930 And another thing I actually want to check real quick is that when we are chasing after a player, let 499 00:34:22,930 --> 00:34:24,610 me figure this out real quick. 500 00:34:24,610 --> 00:34:25,270 Here we go. 501 00:34:25,270 --> 00:34:31,060 When we are chasing after a player, we want to make sure that this player that we are chasing after 502 00:34:31,060 --> 00:34:33,580 and trying to attack hasn't already been jumpscared. 503 00:34:33,580 --> 00:34:40,480 So inside of this until section, we'll also check if this player has the attribute Jumpscared. 504 00:34:41,230 --> 00:34:44,740 So I don't remember if it was jump scare or jump scare. 505 00:34:44,740 --> 00:34:45,520 It was just jump scare. 506 00:34:45,550 --> 00:34:46,060 Okay. 507 00:34:46,120 --> 00:34:52,150 So if this player was inside of a locker they escaped or they've been jump scared or we don't see them 508 00:34:52,150 --> 00:34:55,450 anymore or they died, whatever, we stop chasing after them. 509 00:34:55,480 --> 00:34:56,710 That seems pretty good. 510 00:34:57,800 --> 00:34:58,520 And guess what? 511 00:34:58,520 --> 00:35:03,440 I think we're actually done with our I, Squidward handler. 512 00:35:03,710 --> 00:35:10,100 So because we are calling the start, I function within our game section's module script here. 513 00:35:10,100 --> 00:35:17,000 So after the basement stuff sets up, we start the I, which means we spawn this function right here 514 00:35:17,000 --> 00:35:17,930 in a new thread. 515 00:35:17,930 --> 00:35:24,890 And that means our main function here gets called, which starts looping and starts up our AI to start 516 00:35:24,890 --> 00:35:26,300 wandering around the map. 517 00:35:26,600 --> 00:35:32,570 So the only thing left to do at this point is to test whether or not our AI is actually working. 518 00:35:32,570 --> 00:35:34,640 So let's go ahead and find out. 519 00:35:35,660 --> 00:35:42,050 So after this cutscene, hopefully our AI Squidward, should start to set up and wander around the map. 520 00:35:42,710 --> 00:35:50,690 And unfortunately, we did get an error in the console load animation requires the asset ID not to not 521 00:35:50,690 --> 00:35:51,170 be empty. 522 00:35:51,170 --> 00:35:56,180 Oh, it looks like I accidentally left an asset or an ID in there empty. 523 00:35:56,840 --> 00:35:58,880 I do see glowing eyes back there. 524 00:35:58,880 --> 00:36:02,240 So what does our Squidward doing? 525 00:36:08,180 --> 00:36:12,200 Fortunately, our scooter doesn't look like to be doing much. 526 00:36:12,740 --> 00:36:14,060 That's a little interesting. 527 00:36:18,410 --> 00:36:25,640 I guess we'll have to go ahead and figure out, uh, why our Squidward isn't working with this error 528 00:36:25,640 --> 00:36:26,630 here in particular. 529 00:36:26,630 --> 00:36:32,750 It's just because I accidentally left an animation ID inside of my Squidward empty. 530 00:36:32,750 --> 00:36:39,050 Which was actually, if I go to server storage, we go down to my handsome Squidward. 531 00:36:39,080 --> 00:36:41,360 I inside of animate. 532 00:36:41,360 --> 00:36:42,980 I believe my fall animation. 533 00:36:42,980 --> 00:36:46,730 Yeah, there's nothing in my fall animation, so I'll just input some random number in there. 534 00:36:46,730 --> 00:36:51,470 It doesn't really matter just to make sure that this doesn't get upset, but it looks like we didn't 535 00:36:51,470 --> 00:36:52,580 get any other errors. 536 00:36:52,580 --> 00:36:57,590 It's just that our I, Squidward, was not wandering around the map, so. 537 00:36:58,350 --> 00:37:02,040 Let's go ahead and figure out exactly why that was the case. 538 00:37:06,120 --> 00:37:06,660 All right. 539 00:37:06,660 --> 00:37:13,920 So after a long time of testing and debugging and trying to figure out why our AI wasn't working out 540 00:37:13,920 --> 00:37:19,650 of one of my test iterations, I actually finally got an error message in the console that I made a 541 00:37:19,650 --> 00:37:26,820 typo and the typos in the get nearest visible player function where I spelt character incorrectly, 542 00:37:26,820 --> 00:37:32,820 which is kind of interesting because it didn't show this error until later. 543 00:37:32,820 --> 00:37:37,950 We didn't get this error message the first time, even though this little spelling mistake was the root 544 00:37:37,950 --> 00:37:44,760 of the entire reason for why our AI was not working, this simple little typo, which for some reason 545 00:37:44,760 --> 00:37:48,360 did not appear in the console. 546 00:37:48,360 --> 00:37:53,880 For some reason, I didn't get any error messages until randomly later, which is really weird. 547 00:37:53,880 --> 00:37:56,670 I'm assuming that's some kind of studio bug or something. 548 00:37:56,670 --> 00:38:04,620 But anyways, let's go ahead and fix this typo here to make sure it says character, not character, 549 00:38:04,950 --> 00:38:09,540 and let's go ahead and test out our AI again and see if it actually works this time. 550 00:38:09,960 --> 00:38:12,150 All right we're heading into the basement. 551 00:38:12,480 --> 00:38:16,530 Let's go ahead and hope this time that our AI is actually functioning. 552 00:38:19,200 --> 00:38:23,610 So go ahead and grab my flashlight off the floor, and let's go ahead and see if we can find our little 553 00:38:23,610 --> 00:38:26,670 eye friend wherever he's wandering about. 554 00:38:32,010 --> 00:38:34,890 The most important part is to listen for footsteps. 555 00:38:47,530 --> 00:38:48,760 Oh, there he is. 556 00:38:48,760 --> 00:38:49,630 And there we go. 557 00:38:49,630 --> 00:38:51,550 He's chasing right after us. 558 00:38:53,980 --> 00:38:57,790 Um, that is a little strange. 559 00:38:57,790 --> 00:39:00,820 Why did he run away and not exactly sure? 560 00:39:03,160 --> 00:39:05,920 Well, we can go ahead and test to see if the jump scare works. 561 00:39:09,540 --> 00:39:11,520 Hey, at least the jumpscare works. 562 00:39:11,520 --> 00:39:12,480 That's nice. 563 00:39:12,690 --> 00:39:18,570 But, uh, I think we need to figure out why exactly he ran away from us. 564 00:39:18,570 --> 00:39:21,180 So let's go ahead and figure that out real quick. 565 00:39:22,030 --> 00:39:28,000 Okay, so back into our new path to function, which is responsible for chasing after the player. 566 00:39:28,240 --> 00:39:34,900 As we saw, the AI was pathfinding around the map and eventually after it saw us, it began executing 567 00:39:34,900 --> 00:39:40,600 this repeat loop where he was continually moving towards us until we were no longer visible. 568 00:39:40,600 --> 00:39:45,250 So if you remember, we went around that corner and then all of a sudden he ran away from us. 569 00:39:45,250 --> 00:39:51,790 So we know that after this repeat loop is completed and we disappeared around that corner and he began 570 00:39:51,790 --> 00:39:52,840 to run away from us. 571 00:39:52,840 --> 00:39:55,120 Our issue must be down here somewhere. 572 00:39:55,630 --> 00:40:00,100 So first off, we check if we can get the nearest visible player. 573 00:40:00,100 --> 00:40:02,830 And since we disappeared around the corner, that's not true. 574 00:40:02,830 --> 00:40:07,750 So what we have them do is we have a move to the last position we saw, which is great. 575 00:40:07,750 --> 00:40:09,820 And then we wait for that to finish. 576 00:40:09,820 --> 00:40:17,020 Now, I think our issue here is that because we ran so far away from his pathfinding system, after 577 00:40:17,020 --> 00:40:22,240 this wait event is completed, this goes through the next iteration of a loop and moves to the next 578 00:40:22,240 --> 00:40:24,430 waypoint, which makes sense why? 579 00:40:24,460 --> 00:40:30,700 After this completed and he moved to our last position, he began to sprint away from us back to a different 580 00:40:30,700 --> 00:40:34,570 waypoint position because we're continuing to loop through this for loop. 581 00:40:34,570 --> 00:40:39,430 So a way that we could fix that is we could just simply insert a break statement right here. 582 00:40:39,430 --> 00:40:44,560 So after he moves to the last position, we completely break out of this for loop and exit out of our 583 00:40:44,560 --> 00:40:49,510 new path to function, which allows our Squidward to enter back into this while loop and then begin 584 00:40:49,510 --> 00:40:52,390 to look for another nearest visible player. 585 00:40:52,390 --> 00:40:57,880 So now everything should be working, and we could go ahead and test this out one more time. 586 00:40:58,570 --> 00:41:00,850 All right, we're heading back into the basement. 587 00:41:00,850 --> 00:41:04,690 Hopefully our AI, Squidward, should be working just fine this time. 588 00:41:05,080 --> 00:41:09,760 So let's go ahead and get our flashlight and see if we can find him somewhere. 589 00:41:10,390 --> 00:41:13,930 So the first important thing is to listen for his footsteps. 590 00:41:13,930 --> 00:41:16,570 So take a look around. 591 00:41:18,640 --> 00:41:19,630 And there he is. 592 00:41:19,630 --> 00:41:23,740 So if I disappear around this corner, what does he do? 593 00:41:23,740 --> 00:41:24,400 Oh, perfect. 594 00:41:24,400 --> 00:41:25,150 He doesn't run away. 595 00:41:25,150 --> 00:41:27,070 I don't believe he sees us. 596 00:41:27,190 --> 00:41:28,840 And if we go into the locker. 597 00:41:29,320 --> 00:41:30,070 Perfect. 598 00:41:30,070 --> 00:41:31,450 He leaves us alone. 599 00:41:31,450 --> 00:41:33,940 So if we exit out of the locker, there we go. 600 00:41:33,940 --> 00:41:36,490 He's back again, wandering around the map. 601 00:41:36,820 --> 00:41:39,610 So let me see if I can find a locker somewhere to go hide. 602 00:41:39,610 --> 00:41:40,810 There's one right there. 603 00:41:40,960 --> 00:41:43,360 Oh, we go into our locker. 604 00:41:44,020 --> 00:41:44,860 Perfect. 605 00:41:46,280 --> 00:41:48,920 And there he goes off wandering around our map. 606 00:41:48,920 --> 00:41:54,950 So let's just kind of follow him around and let's see if he disappears once he reaches too many walking 607 00:41:54,950 --> 00:41:56,030 iterations. 608 00:41:56,420 --> 00:41:59,270 So he's continuing to wander around the map. 609 00:41:59,420 --> 00:42:01,940 He has no idea we're behind him. 610 00:42:05,190 --> 00:42:10,740 Oops does appear that we reset his walking iterations, so we're going to have to wait again. 611 00:42:22,500 --> 00:42:22,920 All right. 612 00:42:22,920 --> 00:42:25,020 It's continuing to pathfind around the map. 613 00:42:37,220 --> 00:42:38,870 That's a little spooky, ain't it? 614 00:42:41,210 --> 00:42:41,990 Where'd he go? 615 00:42:47,460 --> 00:42:49,260 Look, you definitely saw us there. 616 00:42:50,010 --> 00:42:53,160 But so far, it looks like our Squidward was working great. 617 00:42:53,160 --> 00:42:55,290 As you can see, he's wandering around the map. 618 00:42:55,350 --> 00:42:59,280 Can't get too close to him or else he'll attack a jump scare us. 619 00:42:59,670 --> 00:43:02,610 And as you can see, he can be quite fast. 620 00:43:02,610 --> 00:43:05,550 So that's a pretty terrifying thing to see chasing after you. 621 00:43:08,150 --> 00:43:10,130 And there he goes off pathfinding again. 622 00:43:10,130 --> 00:43:10,940 Perfect. 623 00:43:11,990 --> 00:43:14,870 So it seems that our AI, Squidward, is working great. 624 00:43:14,870 --> 00:43:20,120 So I believe the next thing we'll have to work on is setting up that spectating system for our players 625 00:43:20,120 --> 00:43:23,210 when we die and get jumpscared by our AI, Squidward. 626 00:43:23,600 --> 00:43:26,510 So I'll go ahead and see you in the next lecture.